package com.ajmd.onlineexam.service;

import com.ajmd.onlineexam.baseUtil.CommonResult;
import com.ajmd.onlineexam.entity.*;
import com.ajmd.onlineexam.enumeration.StaticFinalValue;
import com.ajmd.onlineexam.mapper.*;
import com.ajmd.onlineexam.vo.ExamQuestionVO;
import com.ajmd.onlineexam.vo.OptionVO;
import com.ajmd.onlineexam.vo.QuestionVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author ajmd
 * @since 2023/5/4 13:39
 */
@Service
public class PersonExamService {
    @Resource
    private PersonExamMapper personExamMapper;
    @Resource
    private ExamQuestionMapper examQuestionMapper;
    @Resource
    private OptionMapper optionMapper;
    @Resource
    private ImageMapper imageMapper;
    @Resource
    private PersonAnswerMapper personAnswerMapper;
    @Resource
    private ExamMapper examMapper;
    @Resource
    private StudentMapper studentMapper;

    /**
     * 发布考试时批量创建考生试卷
     * @param studentIds
     * @param examId
     * @return
     */
//    @Async
    public int batchAdd(Set<String> studentIds, String examId){
        List<PersonExamPO> personExamPOList = new ArrayList<>();
        for(String studentId:studentIds){
            PersonExamPO personExamPO = new PersonExamPO();
            personExamPO.setId(UUID.randomUUID().toString());
            personExamPO.setStudentId(studentId);
            personExamPO.setExamId(examId);
            personExamPO.setCreateTime(new Timestamp(System.currentTimeMillis()));
            personExamPO.setScore(BigDecimal.ZERO);
            personExamPO.setStatus(StaticFinalValue.UNEXAMINED);//未考
            personExamPOList.add(personExamPO);
        }
        return personExamMapper.insertBatchSomeColumn(personExamPOList);
    }

    /**
     * 更新考试时删除原来生成的考生考试表记录
     * @param examId
     * @return
     */
    public int batchDelete(String examId){
        LambdaQueryWrapper<PersonExamPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PersonExamPO::getExamId,examId);
        return personExamMapper.delete(queryWrapper);
    }

    /**
     * 获取考试试题
     * @param examId
     * @return
     */
    public List<ExamQuestionVO> getExamQuestion(String examId){
        //根据 examId 查询所有考试试题
        List<ExamQuestionVO> examQuestionVOList = new ArrayList<>();
        LambdaQueryWrapper<ExamQuestionPO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ExamQuestionPO::getExamId,examId)
                .orderByAsc(ExamQuestionPO::getSort);
        List<ExamQuestionPO> examQuestionPOList = examQuestionMapper.selectList(lambdaQueryWrapper);

        if(ObjectUtils.isEmpty(examQuestionPOList)){
            return examQuestionVOList;
        }
        //提取考试试卷ids
        List<String> examQuestionIds = examQuestionPOList.stream().map(ExamQuestionPO::getId).collect(Collectors.toList());
        //查询所有选项
        LambdaQueryWrapper<OptionPO> optionWrapper = new LambdaQueryWrapper<>();
        optionWrapper.in(OptionPO::getBelongQuestionId,examQuestionIds)
                .orderByAsc(OptionPO::getOptionChar);
        List<OptionPO> optionPOList = optionMapper.selectList(optionWrapper);
        List<String> imageBelongIds = new ArrayList<>();

        if(ObjectUtils.isNotEmpty(optionPOList)){
            //从选项中提出选项id，用于图片查询
            List<String> questionIds = optionPOList.stream().map(OptionPO::getId).collect(Collectors.toList());
            imageBelongIds.addAll(questionIds);
        }
        imageBelongIds.addAll(examQuestionIds); //试题id也加入图片查询
        //查询出相关的图片List
        LambdaQueryWrapper<ImagePO> imageWrapper = new LambdaQueryWrapper<>();
        imageWrapper.in(ImagePO::getBelongSecondlyId,imageBelongIds);
        List<ImagePO> imagePOList = imageMapper.selectList(imageWrapper);
        Map<String, List<ImagePO>> imageMap = new HashMap<>();
        if(ObjectUtils.isNotEmpty(imagePOList)){
            //将图像按照归属对象分组存放
            imageMap = imagePOList.stream().collect(Collectors.groupingBy(ImagePO::getBelongSecondlyId));
        }
        //将 optionPOList 转为VOList，并封装进图片
        List<OptionVO> optionVOList = new ArrayList<>();
        if(ObjectUtils.isNotEmpty(optionPOList)){
            for(OptionPO optionPO:optionPOList){
                OptionVO optionVO = new OptionVO();
                BeanUtils.copyProperties(optionPO,optionVO);
                optionVO.setPicList(imageMap.get(optionPO.getId()));
                optionVOList.add(optionVO);
            }
        }
        Map<String, List<OptionVO>> optionVOMap = new HashMap<>();
        if(ObjectUtils.isNotEmpty(optionVOList)){
            //optionVOList按照所属考试试题questionId分组存放
            optionVOMap = optionVOList.stream().collect(Collectors.groupingBy(OptionVO::getBelongQuestionId));
        }
        //遍历试题 examQuestionPOList 进行封装，将 examQuestionPO转为VO，并封装进图片
        for(ExamQuestionPO examQuestionPO:examQuestionPOList){
            ExamQuestionVO examQuestionVO = new ExamQuestionVO();
            BeanUtils.copyProperties(examQuestionPO,examQuestionVO);
            examQuestionVO.setOptionList(optionVOMap.get(examQuestionPO.getId()));
            examQuestionVO.setPicList(imageMap.get(examQuestionPO.getId()));
            examQuestionVOList.add(examQuestionVO);
        }

        return examQuestionVOList;
    }

    /**
     * 修改或新增人员考试表
     * @param studentId
     * @param examId
     * @return
     */
    public Timestamp updateOrAddPersonExam(String studentId, String examId,
                      List<PersonExamPO> personExamPOList,StringBuffer personExamId) {

        Timestamp enterTime = new Timestamp(System.currentTimeMillis());
        personExamId.append(personExamPOList.get(0).getId());
        if(StaticFinalValue.UNEXAMINED.equals(personExamPOList.get(0).getStatus())){
            //此记录未开考过，设置进入考试的时间
            PersonExamPO personExamPO = personExamPOList.get(0);
            personExamPO.setEnterTime(enterTime);
            personExamPO.setStatus(StaticFinalValue.TESTING);
            personExamMapper.updateById(personExamPO);
        }else if(StaticFinalValue.TESTING.equals(personExamPOList.get(0).getStatus())){
            //考试过程中重新进入，返回考试开始时间
            enterTime = personExamPOList.get(0).getEnterTime();
        }else{
            //至少有过一次考试记录，需要增加新的考生考试表记录
            PersonExamPO personExamPO = new PersonExamPO();
            String id = UUID.randomUUID().toString();
            personExamPO.setId(id);
            personExamPO.setStudentId(studentId);
            personExamPO.setExamId(examId);
            personExamPO.setStatus(StaticFinalValue.TESTING);
            personExamPO.setEnterTime(enterTime);
            personExamMapper.insert(personExamPO);
            personExamId.setLength(0);
            personExamId.append(id);
        }
        return enterTime;
    }

    public List<PersonExamPO> getList(String studentId,String examId){
        LambdaQueryWrapper<PersonExamPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PersonExamPO::getStudentId, studentId).eq(PersonExamPO::getExamId, examId)
                .orderByDesc(PersonExamPO::getCreateTime);
        return personExamMapper.selectList(queryWrapper);
    }


    public boolean hasPersonExamRecord(String examId){
        LambdaQueryWrapper<PersonExamPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PersonExamPO::getExamId,examId)
                .ne(PersonExamPO::getStatus,StaticFinalValue.UNEXAMINED);
        List<PersonExamPO> personExamPOList = personExamMapper.selectList(queryWrapper);
        return ObjectUtils.isEmpty(personExamPOList)?false:true;
    }


    //考生考试试题答案保存
    @Transactional
    public int saveAnswer(String account,String personExamId, List<PersonAnswerPO> personAnswerList,
                          boolean submitFlag,String examId){

        PersonExamPO personExamPO = personExamMapper.selectById(personExamId);
        if(personExamPO.getStatus()>1){ //2已完成，3未通过，4已通过
            return -1;
        }

        //删除原来的答案
        LambdaQueryWrapper<PersonAnswerPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PersonAnswerPO::getStudentId,account)
                .eq(PersonAnswerPO::getPersonExamId,personExamId);
        personAnswerMapper.delete(queryWrapper);

        personAnswerList.forEach(item->{
            item.setStudentId(account);
            item.setPersonExamId(personExamId);
            item.setId(UUID.randomUUID().toString());
        });

        if(submitFlag){
            submit(examId,account,personAnswerList,personExamPO);
        }
        //保存新的答案
        return personAnswerMapper.insertBatchSomeColumn(personAnswerList);
    }
    //提交试卷相关操作
    private void submit(String examId, String account, List<PersonAnswerPO> personAnswerList, PersonExamPO personExamPO){
        //1，评分
        BigDecimal studentMaxScore = giveScore(examId, personAnswerList);
        //2，更新考生考试状态
        ExamPO examPO = examMapper.selectById(examId);
//            PersonExamPO personExamPO = new PersonExamPO();
//            personExamPO.setId(personExamId);
        personExamPO.setScore(studentMaxScore);
        if(studentMaxScore.compareTo(BigDecimal.valueOf(examPO.getPassScore()))>=0){
            //学生成绩大于等于通过分数
            personExamPO.setStatus(StaticFinalValue.PASS);
            //增加学分
            LambdaQueryWrapper<PersonExamPO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(PersonExamPO::getExamId,examId)
                    .ge(PersonExamPO::getScore,examPO.getPassScore());
            List<PersonExamPO> personExamPOList = personExamMapper.selectList(lambdaQueryWrapper);
            //同个考试只加一次，先查询有没有通过的记录，有则说明加过了
            if(ObjectUtils.isEmpty(personExamPOList)){
                studentMapper.addCredit(account,examPO.getCredit());
            }
        }else{
            personExamPO.setStatus(StaticFinalValue.NOT_PASS);
        }
        personExamMapper.updateById(personExamPO);
    }

    private BigDecimal giveScore(String examId,List<PersonAnswerPO> personAnswerList){
        //查找考试试题
        LambdaQueryWrapper<ExamQuestionPO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ExamQuestionPO::getExamId,examId);
        List<ExamQuestionPO> examQuestionPOList = examQuestionMapper.selectList(wrapper);
        Map<String, ExamQuestionPO> examQuestionPOMap = examQuestionPOList.stream()
                .collect(Collectors.toMap(ExamQuestionPO::getId, Function.identity()));

        BigDecimal studentMaxScore = BigDecimal.ZERO;

        //评分
        for(PersonAnswerPO item : personAnswerList) {//考生所答对应的考试试题
            ExamQuestionPO examQuestionPO = examQuestionPOMap.get(item.getQuestionId());
            Integer questionType = examQuestionPO.getQuestionType();    //试题类型
            String answer = examQuestionPO.getAnswer(); //正确答案
            String studentAnswer = item.getAnswer();    //考生答案
            BigDecimal maxScore = examQuestionPO.getScore();//试题分值
            //默认给初始值0
            item.setScore(BigDecimal.ZERO);
            if (StaticFinalValue.RADIO.equals(questionType) ||
                    StaticFinalValue.TRUE_OR_FALSE.equals(questionType)) {
                //单选和判断,如果答案相同则给满分
                if (answer.equals(studentAnswer)) {
                    item.setScore(maxScore);
                    studentMaxScore = studentMaxScore.add(maxScore);
                }
                continue;
            }
            if (StaticFinalValue.MULTIPLE.equals(questionType)) {   //多选
                //如果答案相同直接给满分
                if (answer.equals(studentAnswer)) {
                    item.setScore(maxScore);
                    studentMaxScore = studentMaxScore.add(maxScore);
                    continue;
                }
                if (examQuestionPO.getAllowMissing()) {   //允许漏选
                    BigDecimal answerNum = BigDecimal.valueOf(answer.length()); //正确选项个数
                    BigDecimal oneSelectScore = maxScore.divide(
                            answerNum,
                            BigDecimal.ROUND_CEILING
                    ); //单个正确选项分数
                    for (char oneSelect : studentAnswer.toCharArray()) {
                        if (!answer.contains(String.valueOf(oneSelect))) {
                            //正确答案中没有该选项，得分为0，直接返回
                            item.setScore(BigDecimal.ZERO);
                            break;
                        }
                        item.setScore(item.getScore().add(oneSelectScore));
                    }
                    studentMaxScore = studentMaxScore.add(item.getScore());
                }
                continue;
            }
            //不同空答案用|||分隔，若同个空有不同答案则按;分隔
            if (StaticFinalValue.FILL.equals(questionType)) {     //填空
                List<String> answerList = Arrays.asList(answer.split("\\|\\|\\|"));   //正确填空项数组
                List<String> studentAnswerList = Arrays.asList(studentAnswer.split("\\|\\|\\|"));   //考生填空项数组
                BigDecimal answerNum = BigDecimal.valueOf(answerList.size()); //填空项个数
                BigDecimal oneFillScore = maxScore.divide(answerNum,BigDecimal.ROUND_CEILING); //单个空分数
                if(examQuestionPO.getAllowDifficultOrder()){//填空题设置了允许考生答案顺序与正确答案不一致，则同个空只有一个答案
                    for(String fillAnswer:answerList){
                        if(studentAnswerList.indexOf(fillAnswer)!=-1){  //该正确答案在考生答案中出现
                            item.setScore(item.getScore().add(oneFillScore));
                        }
                    }
                    studentMaxScore = studentMaxScore.add(item.getScore());
                    continue;
                }
                for (int i = 0; i < answerList.size(); i++) {
                    String oneAnswer = answerList.get(i);   //第i个空答案（答案有多个
                    String oneStudentAnswer = studentAnswerList.get(i); //考生第i个空答案
                    List<String> oneDiffAnswerList = Arrays.asList(oneAnswer.split(";"));
                    if (oneDiffAnswerList.indexOf(oneStudentAnswer) != -1) {//考生该填空匹配到对应填空项的一个正确答案
                        item.setScore(item.getScore().add(oneFillScore));
                    }
                }
                studentMaxScore = studentMaxScore.add(item.getScore());
                continue;
            }
            if (StaticFinalValue.QUESTION.equals(questionType)) {     //问答
                String answerKey = examQuestionPO.getAnswerKey();
                List<String> keys = Arrays.asList(answerKey.split("\\|\\|\\|"));   //答案关键词数组
                BigDecimal oneKeyScore = maxScore.divide(
                        BigDecimal.valueOf(keys.size()),
                        BigDecimal.ROUND_CEILING
                );  //单个关键词分值
                for (String key : keys) {
                    String regex = ".*" + key + ".*";
                    Pattern pattern = Pattern.compile(regex);
                    Matcher matcher = pattern.matcher(studentAnswer);
                    if (matcher.matches()) {
                        item.setScore(item.getScore().add(oneKeyScore));
                    }
                }
                studentMaxScore = studentMaxScore.add(item.getScore());
                continue;
            }
        }
        return studentMaxScore;
    }
}
